package com.gee.spring.cloud.aerospace.simulate.core.util;

/**
 * @author gee
 * @since 2025/5/15 10:00
 */

import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HexUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import org.springframework.util.Assert;
/**
 * @author gepengjun
 * @since 2024/7/8 9:13
 */
public class ByteUtil {


    /**
     * 字节数组按字节数组值进行替换
     * @param data 源字节数据
     * @param replacePair 替换的对， key: 被替换字节数组， value 替换后的数组
     * @return 替换完成的数据
     */
    public static byte[] replaceBytes(byte[] data, Pair<byte[], byte[]> replacePair){
        if (ArrayUtil.isEmpty(data)){
            return data;
        }
        if (replacePair == null || ArrayUtil.isEmpty(replacePair.getKey())){
            return data;
        }
        byte[] keyBytes = replacePair.getKey();
        byte[] valueBytes = replacePair.getValue();
        int dataLength = data.length;
        int keyLength = keyBytes.length;
        int valueLength = 0;
        if (ArrayUtil.isNotEmpty(valueBytes)){
            valueLength = valueBytes.length;
        }
        ByteBuf byteBuf = Unpooled.buffer();
        int i = 0;
        while (i < dataLength){
            boolean keyMatched = true;
            int i1 = i;
            for (int j = 0; j < keyLength; j++, i1++) {
                if (data[i1] != keyBytes[j]){
                    keyMatched = false;
                    break;
                }
            }
            if (keyMatched && valueLength > 0){
                byteBuf.writeBytes(valueBytes);
                i += keyLength;
            }else {
                byteBuf.writeByte(data[i]);
                i++;
            }
        }
        byte[] result = ByteBufUtil.getBytes(byteBuf);
        byteBuf.release();
        return result;
    }

    public static long bytes2Long(byte[] bytes){
        Assert.isTrue(bytes != null && bytes.length > 0, "byte array must not be null or empty");
        long result = 0;
        for (byte data : bytes) {
            result <<= 8;
            result |= (data & 0xFF);
        }
        return result;
    }

    public static byte[] long2Bytes(long l){
        return HexUtil.decodeHex(HexUtil.toHex(l));
    }

    /**
     *
     * @param bytes 源字节数组
     * @param shiftBits 位移的位数 大于0 表示往右移动， 否则往左移动
     * @return 位移后的结果
     */
    public static byte[] shift(byte[] bytes, long shiftBits){
        if (ArrayUtil.isEmpty(bytes) || shiftBits == 0){
            return bytes;
        }
        if (shiftBits > 0) { //右移
            return shiftRight(bytes, shiftBits);
        }else {
            return shiftLeft(bytes, shiftBits);
        }
    }

    /**
     * 左移
     * @param bytes 源字节数组
     * @param shiftBits 位移的位数 大于0 表示往左移动， 否则往右移动
     * @return 位移后的结果
     */
    public static byte[] shiftLeft(byte[] bytes, long shiftBits) {
        if (ArrayUtil.isEmpty(bytes) || shiftBits == 0){
            return bytes;
        }
        if (shiftBits < 0){
            return shiftRight(bytes, -shiftBits);
        }
        long shiftBitsIn8 = shiftBits % 8;
        long inverseShiftBitsIn8 = 8 - shiftBitsIn8;
        long shiftBytes = shiftBits / 8;
        if (shiftBitsIn8 == 0){
            ByteBuf byteBuf = Unpooled.wrappedBuffer(bytes);
            for (int i = 0; i < shiftBytes; i++) {
                byteBuf.writeByte(0);
            }
            byte[] result = ByteBufUtil.getBytes(byteBuf);
            byteBuf.release();
            return result;
        }
        ByteBuf byteBuf = Unpooled.buffer();
        byte leftBitsInByte = 0;
        for (int i = 0; i <= bytes.length; i++) {
            if (i == bytes.length){
                byteBuf.writeByte(leftBitsInByte);
                continue;
            }
            byte inverseShiftByte = (byte) ((bytes[i] & 0xFF) >> inverseShiftBitsIn8);
            byte data = (byte) (leftBitsInByte | inverseShiftByte);
            leftBitsInByte = (byte) (bytes[i] << shiftBitsIn8);
            byteBuf.writeByte(data);
        }
        for (int i = 0; i < shiftBytes; i++) {
            byteBuf.writeByte(0);
        }
        byte[] result = ByteBufUtil.getBytes(byteBuf);
        byteBuf.release();
        return result;
    }

    public static byte[] shiftRight(byte[] bytes, long shiftBits) {
        if (ArrayUtil.isEmpty(bytes) || shiftBits == 0){
            return bytes;
        }
        if (shiftBits < 0){
            return shiftLeft(bytes, -shiftBits);
        }
        long shiftBitsIn8 = shiftBits % 8;
        long inverseShiftBitsIn8 = 8 - shiftBitsIn8;
        long shiftBytes = shiftBits / 8;
        if (shiftBitsIn8 == 0){
            ByteBuf byteBuf = Unpooled.buffer();
            for (int i = 0; i < shiftBytes; i++) {
                byteBuf.writeByte(0);
            }
            byteBuf.writeBytes(bytes);
            byte[] result = ByteBufUtil.getBytes(byteBuf);
            byteBuf.release();
            return result;
        }
        ByteBuf byteBuf = Unpooled.buffer();
        for (int i = 0; i < shiftBytes; i++) {
            byteBuf.writeByte(0);
        }
        byte leftBitsInByte = 0;
        int bytesLength = bytes.length;
        for (int i = 0; i <= bytesLength; i++) {
            if (i == bytesLength){
                byteBuf.writeByte(leftBitsInByte);
                continue;
            }
            byte data = (byte) ((bytes[i] & 0xFF)>> shiftBitsIn8);
            leftBitsInByte = (byte) (bytes[i] << inverseShiftBitsIn8);
            byteBuf.writeByte(data);
        }
        byte[] result = ByteBufUtil.getBytes(byteBuf);
        byteBuf.release();
        return result;
    }

    public static byte[] interceptOrFillLeft(byte[] bytes, int targetLength){
        if (ArrayUtil.isEmpty(bytes) || targetLength == bytes.length){
            return bytes;
        }
        ByteBuf byteBuf = Unpooled.buffer();
        if (bytes.length < targetLength){
            int i = 0;
            while (i < targetLength - bytes.length){
                byteBuf.writeByte(0);
                i++;
            }
            byteBuf.writeBytes(bytes);
        }else {
            byteBuf.writeBytes(bytes, bytes.length - targetLength , targetLength);
        }
        byte[] result = ByteBufUtil.getBytes(byteBuf);
        byteBuf.release();
        return result;
    }

    /**
     *  字节数组合并，第一个字节数组的最后一个字节和下一个字节数组的第一个字节进行或计算
     * @param bytes1 第一个字节数据
     * @param bytes2 第二个字节数据
     * @return 合并后的字节数组
     */
    public static byte[] mergeWithBit(byte[] bytes1, byte[] bytes2){
        if (bytes1 == null || bytes1.length == 0){
            return bytes2;
        }
        if (bytes2 == null || bytes2.length == 0){
            return bytes1;
        }
        ByteBuf byteBuf = Unpooled.buffer();
        for (int i = 0; i < bytes1.length - 1; i++) {
            byteBuf.writeByte(bytes1[i]);
        }
        byteBuf.writeByte((byte)(bytes1[bytes1.length -1] | bytes2[0]));
        for (int i = 1; i < bytes2.length; i++) {
            byteBuf.writeByte(bytes2[i]);
        }
        byte[] result = ByteBufUtil.getBytes(byteBuf);
        byteBuf.release();
        return result;
    }

    public static byte[] concat(byte[] bytes1, byte[] bytes2){
        if (bytes1 == null || bytes1.length == 0){
            return bytes2;
        }
        if (bytes2 == null || bytes2.length == 0){
            return bytes1;
        }
        byte[] result = new byte[bytes1.length + bytes2.length];
        System.arraycopy(bytes1, 0, result, 0, bytes1.length);
        System.arraycopy(bytes2, 0, result, bytes1.length - 1, bytes2.length);
        return result;
    }

}
